package com.yilin.xbr.core.base;


import com.yilin.xbr.core.exception.BusinessException;
import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.*;


/**
 * Hibernate查询、删除、修改数据操作
 *
 * @author yangyang
 */
public class BaseDao<T> {
    private SessionFactory sessionFactory;
    Logger logger = Logger.getLogger(BaseDao.class);

    @Resource
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    /**
     * 对象保存
     *
     * @param t（实体对象）
     */
    public void save(T t) {
        getSession().save(t);
        getSession().flush();
    }

    /**
     * 删除单条数据
     *
     * @param t（实体对象）
     */
    public void delete(T t) {
        getSession().delete(t);
        getSession().flush();
    }

    /**
     * 修改数据
     *
     * @param t（实体对象）
     */
    public void update(T t) {
        getSession().merge(t);
        getSession().flush();
    }

    /**
     * 修改数据
     *
     * @param t（实体对象）
     */
    public void merge(T t) {
        //使用update方法将会引起冲突，不允许用一个标识标记两个对象
        getSession().merge(t);
        getSession().flush();
    }

    /**
     * 增加或修改数据
     *
     * @param t（实体对象）
     */
    public void saveOrUpdate(T t) {
        getSession().saveOrUpdate(t);
        getSession().flush();
    }

    /**
     * 通过SQL修改数据
     *
     * @param sql（SQL语句）
     * @param objects（需要修改的数据值）
     */
    public void executeSQL(String sql, Object[] objects) {
        Query query = getSession().createSQLQuery(sql);
        if (objects != null && objects.length > 0) {
            for (int i = 0; i < objects.length; i++) {
                query.setParameter(i, objects[i]);
            }
        }
        query.executeUpdate();
    }

    /**
     * 通过SQL修改数据
     */
    protected void executeSQL(String sql, Map<String, Object> map) {
        Query query = getSession().createSQLQuery(sql);
        this.setParameter(query, map);
        query.executeUpdate();
    }

    /**
     * 通过HQL修改数据
     */
    public void executeHQL(String hql, Map<String, Object> map) {
        Query query = getSession().createQuery(hql).setProperties(map);
        query.executeUpdate();
    }

    /**
     * 通过带条件的HQL语句，查询数据
     *
     * @param hql（HQL语句）
     * @param map（查询的条件值）
     */
    public List<T> getListByHql(String hql, Map<String, Object> map) {
        List list = this.getSession().createQuery(hql).setCacheable(false).setProperties(map).list();
        return list;
    }

    /**
     * 通过带条件的HQL语句，查询数据
     *
     * @param hql（HQL语句）
     * @param map（查询的条件值）
     */
    protected List<Map<String,Object>> getListMapByHql(String hql, Map<String, Object> map) {
        List list = this.getSession().createQuery(hql).setCacheable(false)
                .setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
                .setProperties(map).list();
        return list;
    }

    /**
     * 查询指定条数的数据
     *
     * @param hql（HQL语句）
     * @param map（查询的条件值）
     */
    public List<T> getListByHql(String hql, Map<String, Object> map, int maxCount) {
        List list =this.getSession().createQuery(hql).setCacheable(false).setProperties(map).setMaxResults(maxCount).list();
        return list;
    }

    /**
     * 通过SQL查询集合数据，返回类型为List<map>
     *
     * @param sql（SQL语句）
     * @param map（条件值）
     */
    protected List<Map<String, Object>> getListBySQLMap(String sql, Map<String, Object> map) {
        Query query = this.getSession().createSQLQuery(sql).setProperties(map);
        // 设定结果结果集中的每个对象为Map类型
        query.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
        // 执行查询
        List list = query.list();
        return list;
    }

    /**
     * 通过SQL查询集合数据，返回类型为List<map>
     *
     * @param sql（SQL语句）
     * @param map（条件值）
     */
    public List getListBySQL(String sql, Map<String, Object> map) {
        Query query = this.getSession().createSQLQuery(sql).setProperties(map);
        return query.list();
    }

    /**
     * 通过SQL查询集合数据，返回类型为List<map>
     *
     * @param sql（SQL语句）
     * @param map（条件值）
     */
    public List<T> getListBySQL(String sql, Map<String, Object> map,Class vClass) {
        Query query = this.getSession().createSQLQuery(sql).addEntity(vClass).setProperties(map);
        return query.list();
    }

    /**
     * 功能描述： 通过sql返回map对象数据
     */
    public Map<String, Object> getSqlMap(String sql, Map<String, Object> map) {
        Query query = this.getSession().createSQLQuery(sql);
        query = this.setParameter(query, map);
        // 设定结果结果集中的每个对象为Map类型
        query.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
        // 执行查询
        Map<String, Object> map_result = (Map) query.uniqueResult();
        return map_result;
    }

    /**
     * 通过SQL查询集合数据，返回List<map>,条件为Object数组
     */
    public List<Map<String, Object>> getListBySQLMap(String sql, Object[] objects) {
        // 获得SQLQuery对象
        Query query = this.getSession().createSQLQuery(sql);
        if (objects.length > 0) {
            for (int i = 0; i < objects.length; i++) {
                query.setParameter(i, objects[i]);
            }
        }
        // 设定结果结果集中的每个对象为Map类型
        query.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
        // 执行查询
        List list = query.list();
        return list;
    }


    /**
     * 通过简单的HQL查询，返回集合数据
     */
    public List<T> getListByHql(String hql) {
        List<T> list = this.getSession().createQuery(hql).list();
        return list;
    }

    /**
     * 通过ID返回实体对象
     */
    public T getObjectById(Class class1, String id) {
        return (T) getSession().get(class1, id);
    }

    /**
     * 通过HQL查询，返回对象数据
     */
    public T getObjectByColumn(String hql, Map<String, Object> map) {
        return (T) getSession().createQuery(hql).setProperties(map).uniqueResult();
    }

    /**
     * 通过HQL查询，返回对象数据
     */
    public T getSingleByHql(String hql, Map<String, Object> map) {
        List lsTs = getSession().createQuery(hql).setProperties(map).setMaxResults(1).setFirstResult(0).list();
        return (lsTs == null || lsTs.size() == 0) ? null : (T) lsTs.get(0);
    }

    /**
     * 查询分页数据
     */
    public Map<String, Object> getPage(String hql, Map<String, Object> properties, int offset, int length) {
        List<T> list;
        int count = 0;
        String countHql = "";
        if (hql.indexOf("ORDER BY") > 0) {
            countHql = hql.substring(0, hql.indexOf("ORDER BY"));
        } else if (hql.indexOf("order by") > 0) {
            countHql = hql.substring(0, hql.indexOf("order by"));
        } else {
            countHql = hql;
        }
        String countStr;
        if (countHql.contains("FROM")){
            countStr = countHql.split("FROM")[1];
        }else if (countHql.contains("from")){
            countStr = countHql.split("from")[1];
        }else {
            throw new BusinessException("SQL异常");
        }
        String hql_1 = "SELECT count(*) FROM " + countStr;//多少条数据
        Query queryCount = getSession().createQuery(hql_1);
        queryCount = this.setParameter(queryCount, properties);
        Long l = (Long) queryCount.uniqueResult();
        count = Integer.valueOf(l.toString());
        Query query = getSession().createQuery(hql);
        query = this.setParameter(query, properties);
        query.setFirstResult(offset * length);
        query.setMaxResults(length);
        list = query.list();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("total", count);
        map.put("list", list);
        return map;
    }

    /**
     * 查询分页数据
     */
    protected Map<String, Object> getPageSQLMap(String sql, Map<String, Object> properties, int offset, int length) {
        List<Map<String, Object>> list;
        int count = 0;
        String countHql = "";
        if (sql.indexOf("ORDER BY") > 0) {
            countHql = sql.substring(0, sql.indexOf("ORDER BY"));
        } else if (sql.indexOf("order by") > 0) {
            countHql = sql.substring(0, sql.indexOf("order by"));
        } else {
            countHql = sql;
        }
        String hql_1 = "SELECT count(*) FROM " + "(  " + countHql + ")aa";//多少条数据
        Query queryCount = getSession().createSQLQuery(hql_1);
        queryCount = this.setParameter(queryCount, properties);
        BigInteger countBigInteger = (BigInteger) queryCount.uniqueResult();
        count = countBigInteger == null ? 0 : countBigInteger.intValue();
        SQLQuery query = getSession().createSQLQuery(sql);
        query = (SQLQuery) this.setParameter(query, properties);
        query.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
        query.setFirstResult(offset * length);
        query.setMaxResults(length);
        list = query.list();
        Map<String, Object> map = new HashMap<>();
        map.put("total", count);
        map.put("list", list);
        return map;
    }

    /**
     * 通过HQL查询，有多少条数据
     */
    protected int getCountHql(String hql, Map<String, Object> map) {
        int count = 0;
        String hql_1 = "SELECT count(*) " + hql;
        Long l = (Long) getSession().createQuery(hql_1).setProperties(map).uniqueResult();
        count = Integer.valueOf(l.toString());
        return count;
    }

    /**
     * 通过SQL查询，有多少条数据
     */
    protected int getCountSql(String sql, Map<String, Object> map) {
        int count = 0;
        Object object = getSession().createSQLQuery(sql).setProperties(map).uniqueResult();
        if (object == null) {
            object = "0";
        }
        Integer l = Integer.parseInt(object.toString());
        count = l;
        return count;
    }

    //公共方法：设置参数
    protected Query setParameter(Query query, Map<String, Object> map) {
        if (map != null) {
            Set<String> keySet = map.keySet();
            for (String string : keySet) {
                Object obj = map.get(string);
                // 这里考虑传入的参数是什么类型，不同类型使用的方法不同
                if (obj instanceof Collection<?>) {
                    query.setParameterList(string, (Collection<?>) obj);
                } else if (obj instanceof Object[]) {
                    query.setParameterList(string, (Object[]) obj);
                } else {
                    query.setParameter(string, obj);
                }
            }
        }
        return query;
    }
}
